/****************************************************************************
 * Copyright 2010 Huascar A. Sanchez                                        *
 *                                                                          *
 * Licensed under the Apache License, Version 2.0 (the "License");          *
 * you may not use this file except in compliance with the License.         *
 * You may obtain a copy of the License at                                  *
 *                                                                          *
 *     http://www.apache.org/licenses/LICENSE-2.0                           *
 *                                                                          *
 * Unless required by applicable law or agreed to in writing, software      *
 * distributed under the License is distributed on an "AS IS" BASIS,        *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
 * See the License for the specific language governing permissions and      *
 * limitations under the License.                                           *
 ****************************************************************************/
package com.gotobject.greatq.datastore;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.multipart.FilePart;
import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
import org.apache.commons.httpclient.methods.multipart.Part;
import tools.util.StreamPartSource;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.sql.SQLException;
import java.util.Hashtable;
import java.util.concurrent.atomic.AtomicReference;

import static com.gotobject.filter.internal.Objects.as;
import static tools.util.StringUtil.isRealString;
import static tools.util.StringUtil.replaceSubstring;

/**
* @author huascar.sanchez@gmail.com (Huascar A. Sanchez)
*/
class DataFeeder {
    private final DatastoreConnection       connection;
    private final String                    sql;
    private final Hashtable<String, Object> source;

    DataFeeder(DatastoreConnection connection, String sql, Hashtable<String, Object> source) {
        this.connection = connection;
        this.sql = sql;
        this.source = source;
    }


    Hashtable pullData() throws SQLException {
        final String    raw     = connection.propertyOf("url");
        if(raw == null) throw new SQLException("error: url is null");
        final String    addr    = replaceSubstring(raw, " ", "%20");

        final AtomicReference<InputStream> responseStream  = new AtomicReference<InputStream>();
        final HttpClient client          = new HttpClient();

        final PostMethod method          = new PostMethod(addr);

        if (isRealString(connection.propertyOf("user"))) {
            method.addParameter("user", connection.propertyOf("user"));
        }

        if (isRealString(connection.propertyOf("password"))) {
            method.addParameter("password", connection.propertyOf("password"));
        }

        if (isRealString(connection.propertyOf("date.format"))) {
            method.addParameter("date.format", connection.propertyOf("date.format"));
        }

        method.addParameter("query", sql);

        try {
            configure(method);
            return callback(client, method, responseStream);   // unchecked warning
        } catch (Exception e) {
            throw new SQLException(e);
        } finally {
            method.releaseConnection();
        }
    }

    Hashtable callback(HttpClient client, PostMethod method, AtomicReference<InputStream> responseStream) throws
            IOException, ClassNotFoundException {
        final int statusCode = client.executeMethod(method);
        if(HttpStatus.SC_OK != statusCode){
            throw new IOException("error: method failed. Reason: " + method.getStatusLine());
        }

        responseStream.compareAndSet(responseStream.get(), method.getResponseBodyAsStream());
        final ObjectInputStream ois = new ObjectInputStream(responseStream.get());

        return as(ois.readObject());
    }

    void configure(PostMethod method) throws IOException {
        if(!source.isEmpty()){
            final NameValuePair[] pairs = method.getParameters();
            final Hashtable<String, String> freshContent = new Hashtable<String, String>();
            for(NameValuePair each : pairs){
                freshContent.put(each.getName(), each.getValue());
            }

            source.put("parameters", freshContent);
            final ByteArrayOutputStream baos = new ByteArrayOutputStream();
            final ObjectOutputStream oos  = new ObjectOutputStream(baos);
            oos.writeObject(source);
            oos.flush();
            final InputStream is = new ByteArrayInputStream(baos.toByteArray());
            final StreamPartSource sps = new StreamPartSource("directValues", is, is.available());
            final Part[] parts = {new FilePart("defaultValues",sps)};
            method.setRequestEntity(new MultipartRequestEntity(parts, method.getParams()));
        }
    }
}
